package cn.sylinx.hbatis.db.dialect;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import cn.sylinx.hbatis.db.common.FS;
import cn.sylinx.hbatis.db.dialect.sql.SqlBuilder;
import cn.sylinx.hbatis.db.dialect.sql.SqlBuilderFactory;
import cn.sylinx.hbatis.type.TypeHandler;
import cn.sylinx.hbatis.type.TypeHandlerRegistry;

@SuppressWarnings("unchecked")
public abstract class DefaultDialect implements Dialect {

	@Override
	public void setParameters(PreparedStatement pst, Object... params) throws SQLException {

		for (int i = 0, size = params.length; i < size; i++) {
			setParameter(pst, i + 1, params[i]);
		}
	}

	protected <T> void setParameter(PreparedStatement pst, int index, T param) throws SQLException {

		TypeHandler<T> handler = crateTypeHandler(param);
		if (handler != null) {
			handler.setParameter(pst, index, param, null);
		} else {
			pst.setObject(index, param);
		}
	}

	private <T> TypeHandler<T> crateTypeHandler(T param) {

		if (param == null) {
			return null;
		}

		Class<T> clz = (Class<T>) param.getClass();
		return TypeHandlerRegistry.getInstance().getTypeHandler(clz);
	}

	@Override
	public void setParameters(PreparedStatement pst, List<Object> params) throws SQLException {
		for (int i = 0, size = params.size(); i < size; i++) {
			setParameter(pst, i + 1, params.get(i));
		}
	}

	@Override
	public <T> T getResult(ResultSet rs, String columnName, Class<T> clz) throws SQLException {

		TypeHandler<T> handler = TypeHandlerRegistry.getInstance().getTypeHandler(clz);
		if (handler != null) {
			return handler.getResult(rs, columnName);
		}

		return (T) rs.getObject(columnName);
	}

	@Override
	public <T> T getResult(ResultSet rs, int columnIndex, Class<T> clz) throws SQLException {

		TypeHandler<T> handler = TypeHandlerRegistry.getInstance().getTypeHandler(clz);
		if (handler != null) {
			return handler.getResult(rs, columnIndex);
		}

		return (T) rs.getObject(columnIndex);
	}

	@Override
	public <T> T getResult(CallableStatement cs, int columnIndex, Class<T> clz) throws SQLException {

		TypeHandler<T> handler = TypeHandlerRegistry.getInstance().getTypeHandler(clz);
		if (handler != null) {
			return handler.getResult(cs, columnIndex);
		}

		return (T) cs.getObject(columnIndex);
	}

	@Override
	public SqlBuilder getSqlBuilder() {
		return SqlBuilderFactory.get().getSqlBuilder(getDbType());
	}

	@Override
	public <T> FS<T> createFluentSql(Class<T> clazz) {
		return FS.of(clazz);
	}

}
